import java.util.HashMap;
import java.util.Vector;


public class MinMaxOnly implements Play {

	
	private HashMap<String, Board > visited = new HashMap< String, Board>();
	private int depthT;
	private Evaluation ev;
	@Override
	public Move play(Board pBoard, Deadline pDue, int depthT, Evaluation ev) {
		this.depthT = depthT;
		this.ev = ev;
		 Vector<Move> lMoves=new Vector<Move>();
	       
        pBoard.FindPossibleMoves(lMoves,Board.OWN);
       
        if(lMoves.isEmpty()){
        	return Move.cPass;
        }
        
        if (lMoves.size() == 1)
        {
        	return lMoves.firstElement(); 
        }
		this.visited = new HashMap<String, Board>();
        double maxValue = Double.MIN_VALUE;
        int bestMove = 0;
        for (int i = 0; i<lMoves.size();i++)
        {
        	
        	Board nextBoard = new Board(pBoard, lMoves.elementAt(i));
        	String boardS = nextBoard.BoardToString();
        	if (!visited.containsKey(boardS))
        	{
        		visited.put(boardS,nextBoard);
        		double tempV = minValue(nextBoard, depthT);
    			if (tempV > maxValue)
    			{
    				maxValue = tempV;
    				bestMove = i;
    			}
        	}
        	
        }
        System.out.println(pDue.TimeUntil());
        return lMoves.elementAt(bestMove);
	}
	
	double minValue(Board board, int depth)//, double alpha, double beta, Deadline pDue)
    {
    	Vector<Move> moves = new Vector<Move>();
		board.FindPossibleMoves(moves, Board.OTHER);
		Vector<Move> moves1 = new Vector<Move>();
		board.FindPossibleMoves(moves1, Board.OWN);
    	 int ownMobility = moves1.size();
         int opponentMobility = moves.size(); 
         boolean gameEnd = (ownMobility == 0 && opponentMobility == 0);
         
    	if (depth == 0 || (Board.OTHER+Board.OWN) == (Board.cSize*Board.cSize) || gameEnd)
    	{
    		return evaluationfunction(board);
    	}
    	
    	
		double v = Integer.MAX_VALUE;
		moves = new Vector<Move>();
		board.FindPossibleMoves(moves, Board.OTHER);
		
		for (int i = 0; i< moves.size();i++)
		{
			Board nextBoard = new Board(board, moves.elementAt(i));
			String boardS = nextBoard.BoardToString();
        	if (!visited.containsKey(boardS))
        	{
        		visited.put(boardS,nextBoard);
				double tempV = maxValue(nextBoard, depth-1);//, alpha, beta, pDue);
				if (tempV < v)
				{
					v = tempV;
				}
        	}
		}
		return v;
    	
    }
    
    
    
    double maxValue(Board board, int depth)//, double alpha, double beta, Deadline pDue)
    {
    	Vector<Move> moves = new Vector<Move>();
		board.FindPossibleMoves(moves, Board.OTHER);
		Vector<Move> moves1 = new Vector<Move>();
		board.FindPossibleMoves(moves1, Board.OWN);
    	 int ownMobility = moves1.size();
         int opponentMobility = moves.size(); 
         boolean gameEnd = (ownMobility == 0 && opponentMobility == 0);
         
    	if (depth == 0 || Board.OTHER+Board.OWN == Board.cSize*Board.cSize || gameEnd)
    	{
    		
    		return evaluationfunction(board);
    	}

    	double v = Integer.MIN_VALUE;
    	moves = new Vector<Move>();
		board.FindPossibleMoves(moves, Board.OWN);
    	
		for (int i = 0; i< moves.size();i++)
		{
			Board nextBoard = new Board(board, moves.elementAt(i));
			String boardS = nextBoard.BoardToString();
        	if (!visited.containsKey(boardS))
        	{
        		visited.put(boardS, nextBoard);
				
				double tempV = minValue(nextBoard, depth-1);//, alpha, beta, pDue);
				if (tempV > v)
				{
					v = tempV;
				}
        	}
        	
		}
		return v;
    	
    }
    

    private double evaluationfunction(Board board)
    {	
    	return ev.evaluateBoard(board);
    }

}
